package com.dap.utils;

import com.dap.cache.common.serializer.JdkRedisSerializer;
import com.dap.cache.common.serializer.RedisSerializer;

import java.io.ByteArrayOutputStream;

/**
 * Created by wangmin on 2019/4/25.
 */
public class RedisStringDeserializeUtil {
    public static void main(String[] args) {
        //String s = "\\xac\\xed\\x00\\x05sr\\x009com.sbp.foundation.service.vo.param.MessageCodeRedisParam\\xa8/\\xd0\\x0c\\xf8\\xb4_O\\x02\\x00\\x11L\\x00\\x05appIdt\\x00\\x13Ljava/lang/Integer;L\\x00\\x10businessTypeListt\\x00\\x10Ljava/util/List;L\\x00\\x0ediySendContentt\\x00\\x12Ljava/lang/String;L\\x00\\x06expiret\\x00\\x10Ljava/lang/Long;L\\x00\\x06fieldst\\x00\\x0fLjava/util/Map;L\\x00\\ngmtTriggert\\x00\\x10Ljava/util/Date;L\\x00\\rmassMobileSett\\x00\\x0fLjava/util/Set;L\\x00\\x0bmessageCodeq\\x00~\\x00\\x03L\\x00\\x0bmessageTypeq\\x00~\\x00\\x03L\\x00\\x06mobileq\\x00~\\x00\\x03L\\x00\\tsessionIdq\\x00~\\x00\\x03L\\x00\\x0esmsPurposeTypeq\\x00~\\x00\\x01L\\x00\\x0bsmsTemplateq\\x00~\\x00\\x03L\\x00\\asmsTypeq\\x00~\\x00\\x03L\\x00\\ttimestampq\\x00~\\x00\\x04L\\x00\\buseQueueq\\x00~\\x00\\x01L\\x00\\x0fvalidateRetriesq\\x00~\\x00\\x01xpsr\\x00\\x11java.lang.Integer\\x12\\xe2\\xa0\\xa4\\xf7\\x81\\x878\\x02\\x00\\x01I\\x00\\x05valuexr\\x00\\x10java.lang.Number\\x86\\xac\\x95\\x1d\\x0b\\x94\\xe0\\x8b\\x02\\x00\\x00xp\\x00\\x00\\x00\\x02pppsr\\x00\\x11java.util.HashMap\\x05\\a\\xda\\xc1\\xc3\\x16`\\xd1\\x03\\x00\\x02F\\x00\\nloadFactorI\\x00\\tthresholdxp?@\\x00\\x00\\x00\\x00\\x00\\x0cw\\b\\x00\\x00\\x00\\x10\\x00\\x00\\x00\\x02t\\x00\\x04codet\\x00\\x06471223t\\x00\\x06expiret\\x00\\x015xppq\\x00~\\x00\\x0fpt\\x00\\x0b10000000111psq\\x00~\\x00\\t\\x00\\x00\\x00\\x01t\\x00\\x013t\\x00\\asms0003ppp";
        //MessageCodeRedisParam param = parseObject(s, MessageCodeRedisParam.class);
        //System.out.println(JSON.toJSONString(param));
    }

    public static <T> T parseObject(String s, Class<T> clazz) {
        RedisSerializer redisSerializer = new JdkRedisSerializer();
        return parseObject(s, clazz, redisSerializer);
    }
    
    public static <T> T parseObject(String s, Class<T> clazz, RedisSerializer redisSerializer) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        for (int i=0; i<s.length(); ) {
            char ch = s.charAt(i);
            if (ch != '\\') {
                baos.write(ch);

                ++i;
            } else {
                char ch1 = s.charAt(i+1);

                if (ch1 == 'x') {
                    int ch2 = s.charAt(i + 2);
                    ch2 = hexChar2Value(ch2);

                    int ch3 = s.charAt(i + 3);
                    ch3 = hexChar2Value(ch3);

                    int value = (ch2 << 4) + ch3;
                    baos.write(value);

                    i += 4;
                } else {
                    int value;
                    value = convertChar(ch1);
                    baos.write(value);

                    i += 2;
                }
            }
        }

        return redisSerializer.deserializeObjectByClass(baos.toByteArray(), clazz);
    }

    private static int convertChar(char ch) {
        switch (ch) {
            case '0':
                return 0;
            case 'a':
                return 7;//'\a';
            case 'b':
                return '\b';
            case 'f':
                return '\f';
            case 'n':
                return '\n';
            case 'r':
                return '\r';
            case 't':
                return '\t';
            case 'v':
                return 11;//'\v';
            case '\\':
                return '\\';
            case '\'':
                return '\'';
            case '"':
                return '"';
            case '?':
                return '?';

            default:
                return ch;
        }
    }

    private static int hexChar2Value(int ch) {
        if (ch >= '0' && ch <= '9') {
            return ch - '0';
        } else if (ch >= 'a' && ch <= 'f') {
            return ch - ('a' - 10);
        } else if (ch >= 'A' && ch <= 'F') {
            return ch - ('A' - 10);
        }
        throw new RuntimeException("invalid value="+ch);
    }
}
